package com.zhss.dfs.server;

import com.zhss.dfs.server.model.LogDiskRecorder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 负责管理edits log日志的核心组件
 *
 * @author zhonghuashishan
 */
public class FSEditlog {

    /**
     * 当前递增到的txid的序号
     */
    private long txidSeq = 0L;
    /**
     * 内存双缓冲区
     */
    private DoubleBuffer doubleBuffer = new DoubleBuffer();

    /**
     * 在同步到磁盘中的最大的一个txid
     */
    private volatile Long syncMaxTxid = 0L;
    /**
     * 每个线程自己本地的txid副本
     */
    private ThreadLocal<Long> localTxid = new ThreadLocal<Long>();


    /**
     * 返回当前缓冲数据中的内容
     */
    public String[] getCurrentBuffer() {
        synchronized (this) {
            byte[] currentBuffer = this.doubleBuffer.getCurrentBuffer();
            if (currentBuffer.length == 0) {
                return  null;
            }
            return new String(currentBuffer).split("\n");
        }
    }

    /**
     *  获取持久化到磁盘的记录
     * @return
     */
    public List<LogDiskRecorder> getDiskLogData() {
        synchronized (this) {
            return this.doubleBuffer.getDiskLogData();
        }
    }


    public boolean flush(){
        try {
            doubleBuffer.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }


    /**
     * 记录edits log日志
     *
     * @param content
     */
    public void logEdit(String content) {
        // 这里必须得直接加锁
        synchronized (this) {
            txidSeq++;
            long txid = txidSeq;
            localTxid.set(txid);
            // 构造一条edits log对象
            EditLog log = new EditLog(txid, content);
            // 将edits log写入内存缓冲中，不是直接刷入磁盘文件
            try {
                doubleBuffer.write(log);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 每一次写入缓冲区后，判断是否满了
            if (!doubleBuffer.shouldSyncToDisk()) {
                return;
            }
            if (txid <= syncMaxTxid) {
                return;
            }
            // 交换两块缓冲区
            doubleBuffer.setReadyToSync();
            syncMaxTxid = txid;
            try {
                doubleBuffer.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void addDiskLogRecorder(LogDiskRecorder diskRecorder) {
        doubleBuffer.addDiskRecorder(diskRecorder);
    }
}
